/** 
 * ArrayText.java
 * @author Lex
 * 2007-9-2 ����07:13:32
 */
package org.lex.utils.text;

import java.util.Arrays;

public class TextBlock implements CharSequence, Appendable {
	private static final int DEFAULT_CAPACITY = 8;
	// ===========================
	protected char[] data = null;
	protected int count = 0;

	public TextBlock() {
		this(DEFAULT_CAPACITY);
	}

	public TextBlock(int capacity) {
		this.data = new char[capacity];
		this.count = 0;
	}

	public TextBlock append(char c) {
		this.ensureCapacity(count + 1);
		data[count++] = c;
		return this;
	}

	public TextBlock append(char[] value) {
		if (null == value)
			return this;
		return this.append(value, 0, value.length);
	}

	public TextBlock append(char[] value, int offset, int length) {
		if (null == value)
			return this;
		if (offset < 0 || offset >= value.length)
			throw new IndexOutOfBoundsException("Index out of range: " + offset);
		if (length < 0 || length + offset > value.length)
			new IndexOutOfBoundsException("Index out of range: " + length);
		this.ensureCapacity(count + length);
		System.arraycopy(value, offset, data, count, length);
		return this;
	}

	public TextBlock append(CharSequence csq, int start, int end) {
		if (null == csq)
			return this;
		// check range
		int len = csq.length();
		if (start < 0 || start >= len)
			throw new IndexOutOfBoundsException("Index out of range: " + start);
		if (end < start || end > len)
			throw new IndexOutOfBoundsException("Index out of range: " + end);
		// ========================================
		this.ensureCapacity(count + end - start);
		for (int i = start; i < end; i++)
			data[count++] = csq.charAt(i);
		return this;
	}

	public TextBlock append(CharSequence csq) {
		return this.append(csq, 0, csq.length());
	}

	public char charAt(int index) {
		if (index >= count)
			throw new ArrayIndexOutOfBoundsException(index);
		return data[index];
	}

	public ImmutableCharSequence subSequence(int start, int end) {
		return new ImmutableCharSequence(data, start, end - start);
	}

	public int length() {
		return this.count;
	}

	public String toString() {
		return new String(data, 0, count);
	}

	public ImmutableCharSequence toImmutableCharSequence() {
		return this.subSequence(0, count);
	}

	public TextBlock setLength(int length) {
		if (length < 0)
			throw new IndexOutOfBoundsException("Index out of range: " + length);
		if (length < count)
			this.count = length;
		if (length > this.getCapacity())
			this.ensureCapacity(length);
		return this;
	}

	public int getCapacity() {
		return data.length;
	}

	public void trimToSize() {
		if (data.length > count)
			data = Arrays.copyOf(data, count);
	}

	protected void ensureCapacity(int min) {
		if (min > data.length) {
			int newSize = data.length * 2;
			if (newSize <= 0)
				newSize = Integer.MAX_VALUE;
			if (newSize < min)
				newSize = min;
			data = Arrays.copyOf(data, newSize);
		}
	}
}
